package org.csu.onlineedubackend.util;

import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Item;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jakarta.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
public class FileUtil {

    private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);

    private final long maxFileSize=1000;

    // MinIO 配置
    @Value("${minio.endpoint}")
    private String minioEndpoint;

    @Value("${minio.access-key}")
    private String minioAccessKey;

    @Value("${minio.secret-key}")
    private String minioSecretKey;

    private MinioClient minioClient;

    // 支持的文件类型映射
    private static final Map<String, String[]> ALLOWED_EXTENSIONS = new HashMap<>();

    static {
        // 图片类型
        ALLOWED_EXTENSIONS.put("image", new String[]{"jpg", "jpeg", "png", "gif", "bmp", "webp", "svg"});
        // 视频类型
        ALLOWED_EXTENSIONS.put("video", new String[]{"mp4", "avi", "mov", "wmv", "flv", "webm", "mkv"});
        // 文件类型
        ALLOWED_EXTENSIONS.put("document", new String[]{"pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt"});
        // 音频类型
        ALLOWED_EXTENSIONS.put("audio", new String[]{"mp3", "wav", "flac", "aac", "ogg", "wma"});
        // 压缩文件类型
        ALLOWED_EXTENSIONS.put("archive", new String[]{"zip", "rar", "7z", "tar", "gz"});
    }

    @PostConstruct
    public void init() {
        // 在属性注入完成后初始化 MinIO 客户端
        minioClient = MinioClient.builder()
                .endpoint(minioEndpoint)
                .credentials(minioAccessKey, minioSecretKey)
                .build();
    }

    // 根據文件擴展名確定文件類型
    String getFileTypeByExtension(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "unknown";
        }

        String extension = getFileExtension(fileName).toLowerCase();

        for (Map.Entry<String, String[]> entry : ALLOWED_EXTENSIONS.entrySet()) {
            if (Arrays.asList(entry.getValue()).contains(extension)) {
                return entry.getKey();
            }
        }

        return "unknown";
    }

    // 獲取文件擴展名
    String getFileExtension(String fileName) {
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex > 0 && lastDotIndex < fileName.length() - 1) {
            return fileName.substring(lastDotIndex + 1);
        }
        return "";
    }

    // 根據文件類型確定存儲桶名稱
    String getCategoryBucket(String fileType) {
        switch (fileType.toLowerCase()) {
            case "image":
                return "images-bucket";
            case "video":
                return "videos-bucket";
            case "document":
                return "docs-bucket";
            case "audio":
                return "audio-bucket";
            case "archive":
                return "archives-bucket";
            default:
                return "others-bucket";
        }
    }

    // 驗證文件類型是否允許
    boolean isAllowedFileType(String fileName) {
        String fileType = getFileTypeByExtension(fileName);
        return !"unknown".equals(fileType);
    }

    // 驗證文件大小
    boolean isFileSizeValid(long fileSize) {
        return fileSize <= maxFileSize * 1024 * 1024; // 轉換為字節
    }



    // 上传文件到 MinIO
    // 上传文件到 MinIO（使用 UUID + 时间戳生成唯一名）
    private String uploadToMinioServer(MultipartFile file, String bucketName, String uniqueFileName) throws IOException {
        try {
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (!isExist) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }

            try (InputStream inputStream = file.getInputStream()) {
                minioClient.putObject(
                        PutObjectArgs.builder()
                                .bucket(bucketName)
                                .object(uniqueFileName)
                                .stream(inputStream, file.getSize(), -1)
                                .contentType(file.getContentType())
                                .build()
                );
            }

            return minioEndpoint + "/" + bucketName + "/" + uniqueFileName;
        } catch (MinioException | InvalidKeyException | NoSuchAlgorithmException e) {
            throw new IOException("MinIO 上传失败: " + e.getMessage(), e);
        }
    }

    // 只保留一个上传方法，自动生成唯一文件名
    public String uploadFile(MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
        if (!isFileSizeValid(file.getSize())) {
            throw new IllegalArgumentException("文件大小超过限制：" + maxFileSize + "MB");
        }
        if (!isAllowedFileType(file.getOriginalFilename())) {
            throw new IllegalArgumentException("不支持的文件类型");
        }

        String fileType = getFileTypeByExtension(file.getOriginalFilename());
        String bucketName = getCategoryBucket(fileType);

        // 唯一文件名：时间戳 + UUID + .扩展名
        String extension = getFileExtension(file.getOriginalFilename());
        String uniqueFileName = System.currentTimeMillis() + "_" + UUID.randomUUID().toString() + "." + extension;

        return uploadToMinioServer(file, bucketName, uniqueFileName);
    }

    // 获取 MinIO 文件信息
    public Map<String, Object> getMinioFileInfo(String fileName) {
        Map<String, Object> fileInfo = new HashMap<>();
        try {
            String fileType = getFileTypeByExtension(fileName);
            String bucketName = getCategoryBucket(fileType);
            var stat = minioClient.statObject(
                    StatObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName)
                            .build()
            );
            fileInfo.put("fileName", fileName);
            fileInfo.put("fileSize", stat.size());
            fileInfo.put("lastModified", stat.lastModified());
            fileInfo.put("contentType", stat.contentType());
        } catch (MinioException | InvalidKeyException | NoSuchAlgorithmException | IOException e) {
            // 忽略异常
        }
        return fileInfo;
    }

    // 从 MinIO 下载文件
    public InputStream downloadFromMinio(String fileName) throws IOException {
        try {
            String fileType = getFileTypeByExtension(fileName);
            String bucketName = getCategoryBucket(fileType);
            return minioClient.getObject(
                GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .build()
            );
        } catch (MinioException | InvalidKeyException | NoSuchAlgorithmException e) {
            throw new IOException("MinIO 下载失败: " + e.getMessage(), e);
        }
    }

    // 文件下载方法（保持向后兼容）
    public File downloadFile(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new IllegalArgumentException("文件不存在：" + filePath);
        }
        return file;
    }

    // 从 MinIO 删除文件
    public boolean deleteFromMinio(String fileName) {
        try {
            String fileType = getFileTypeByExtension(fileName);
            String bucketName = getCategoryBucket(fileType);
            minioClient.removeObject(
                RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .build()
            );
            return true;
        } catch (MinioException | InvalidKeyException | NoSuchAlgorithmException | IOException e) {
            return false;
        }
    }

    // 删除文件方法（保持向后兼容）
    public boolean deleteFile(String filePath) {
        try {
            Path path = Paths.get(filePath);
            return Files.deleteIfExists(path);
        } catch (IOException e) {
            return false;
        }
    }

    // 获取文件信息（保持向后兼容）
    public Map<String, Object> getFileInfo(String filePath) {
        Map<String, Object> fileInfo = new HashMap<>();
        try {
            Path path = Paths.get(filePath);
            if (Files.exists(path)) {
                fileInfo.put("fileName", path.getFileName().toString());
                fileInfo.put("fileSize", Files.size(path));
                fileInfo.put("fileType", getFileTypeByExtension(path.getFileName().toString()));
                fileInfo.put("lastModified", Files.getLastModifiedTime(path));
            }
        } catch (IOException e) {
            // 忽略异常
        }
        return fileInfo;
    }

    public List<String> listFiles(String bucketName) throws Exception {
        List<String> urls = new ArrayList<>();
        Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).build());

        for (Result<Item> result : results) {
            Item item = result.get();
            String objectName = item.objectName();
            String fileUrl = minioEndpoint + "/" + bucketName + "/" + objectName;
            urls.add(fileUrl);
        }

        return urls;
    }

    /**
     * 检查指定的存储桶是否存在
     * @param bucketName 存储桶名称
     * @return 存在返回true，不存在返回false
     * @throws Exception 如果检查过程中发生错误
     */
    public boolean bucketExists(String bucketName) throws Exception {
        try {
            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            logger.error("检查存储桶是否存在时出错: {}", bucketName, e);
            throw e;
        }
    }
}
